import { ChildProcess, fork } from "child_process";
import { EventEmitter } from "events";
import { join } from "path";
import { doTiny } from "./child";

export class ChildUnit {
    private cp: ChildProcess;
    constructor() {
        this.create();
    }

    private create() {
        if (this.cp) {
            this.cp.stderr.removeAllListeners();
            this.cp.kill();
        }

        this.cp = fork(join(__dirname, 'child.js'));
    }

    private reset(tt) {
        this.cp.removeAllListeners("message");
        this.cp.removeAllListeners("error");
        if (tt) {
            clearTimeout(tt);
        }
    }

    private doTiny(key: string, info: Buffer, timeout: number) {
        return new Promise<{ data: Buffer, count: number }>((r, j) => {
            let tt;
            if (timeout) {
                tt = setTimeout(() => {
                    this.create()
                    j("time out")
                }, timeout * 1000)
            }
            this.cp.send(JSON.stringify({ key, info }));
            this.cp.once("message", (e) => {
                this.reset(tt);
                r(JSON.parse(e.toString()) as any)
            })

            this.cp.once("error", (e) => {
                this.reset(tt);
                j(e.message)
            })
        })
    }

    async tiny(key: string, info: Buffer, retry?: number, timeout?: number) {
        for (let i = 0; i < (retry || 1); i++) {
            try {
                let result = await this.doTiny(key, info, timeout || 0);
                return Object.assign(result, { succ: true });
            }
            catch (e) {
                console.warn("tiny error", e)
            }
        }

        // return doTiny(key, info)
    }

    get pid() {
        return this.cp.pid;
    }

    destory() {
        if (this.cp) {
            // this.cp.stderr.removeAllListeners();
            this.cp.kill();
            this.cp = null;
        }
    }
}
